package http.secure.common.util.steganography;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 基于字体文件结构的真实字体隐写算法
 * 利用字体表结构进行信息隐藏
 */
public class FontSteganography {

    // TTF字体表签名（用于定位字形数据）
    private static final String GLYF_TABLE = "glyf";

    /**
     * 在字体文件中隐藏信息（基于字体表结构）
     *
     * @param fontBytes 原始字体数据
     * @param message   要隐藏的信息
     * @return 隐写后的字体二进制数据
     */
    public static byte[] hideMessage(byte[] fontBytes, String message) {
        try {
            // 解析字体表结构
            FontTables fontTables = parseFontTables(fontBytes);
            if (fontTables == null) {
                throw new IllegalStateException("无效的字体文件格式");
            }
            // 在字形数据中隐藏信息
            byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8);
            byte[] stegoFont = embedInGlyphData(fontBytes, fontTables, messageBytes);
            if (stegoFont == null) {
                throw new IllegalStateException("字体隐写失败：容量不足");
            }
            return stegoFont;
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage());
        }
    }

    /**
     * 解析字体表结构
     */
    private static FontTables parseFontTables(byte[] fontData) {
        try {
            if (fontData.length < 12) return null;
            // 检查字体签名（0x00010000 for TTF）
            long signature = ((fontData[0] & 0xFFL) << 24) |
                    ((fontData[1] & 0xFFL) << 16) |
                    ((fontData[2] & 0xFFL) << 8) |
                    (fontData[3] & 0xFFL);
            // 读取表数量
            int numTables = ((fontData[4] & 0xFF) << 8) | (fontData[5] & 0xFF);
            FontTables tables = new FontTables();
            // 解析每个表的信息
            int tableRecordOffset = 12;
            for (int i = 0; i < numTables && tableRecordOffset + 16 <= fontData.length; i++) {
                int recordOffset = tableRecordOffset + i * 16;
                // 表名（4字节）
                String tableName = new String(Arrays.copyOfRange(fontData, recordOffset, recordOffset + 4));
                // 校验和（4字节）
                long checksum = ((fontData[recordOffset + 4] & 0xFFL) << 24) |
                        ((fontData[recordOffset + 5] & 0xFFL) << 16) |
                        ((fontData[recordOffset + 6] & 0xFFL) << 8) |
                        (fontData[recordOffset + 7] & 0xFFL);
                // 偏移量（4字节）
                long offset = ((fontData[recordOffset + 8] & 0xFFL) << 24) |
                        ((fontData[recordOffset + 9] & 0xFFL) << 16) |
                        ((fontData[recordOffset + 10] & 0xFFL) << 8) |
                        (fontData[recordOffset + 11] & 0xFFL);
                // 长度（4字节）
                long length = ((fontData[recordOffset + 12] & 0xFFL) << 24) |
                        ((fontData[recordOffset + 13] & 0xFFL) << 16) |
                        ((fontData[recordOffset + 14] & 0xFFL) << 8) |
                        (fontData[recordOffset + 15] & 0xFFL);
                tables.tables.put(tableName, new FontTables.TableInfo(checksum, offset, length));
            }
            return tables;
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage());
        }
    }

    /**
     * 在字形数据中嵌入信息
     */
    private static byte[] embedInGlyphData(byte[] fontData, FontTables fontTables, byte[] message) {
        try {
            // 查找glyf表（字形数据表）
            FontTables.TableInfo glyfTable = fontTables.tables.get(GLYF_TABLE);
            if (glyfTable == null) {
                throw new IllegalStateException("未找到glyf表");
            }
            // 检查容量
            long availableSpace = glyfTable.length;
            long requiredSpace = message.length + 32; // 加上头部信息
            if (availableSpace < requiredSpace) {
                throw new IllegalStateException("字形数据空间不足：" + availableSpace + " < " + requiredSpace);
            }
            // 创建要嵌入的数据（包含头部）
            byte[] header = createFontHeader(message.length);
            byte[] dataToEmbed = new byte[header.length + message.length];
            System.arraycopy(header, 0, dataToEmbed, 0, header.length);
            System.arraycopy(message, 0, dataToEmbed, header.length, message.length);
            // 在字形数据区域嵌入信息
            byte[] result = fontData.clone();
            int embedOffset = (int) glyfTable.offset;
            // 使用LSB技术嵌入数据
            boolean[] bits = bytesToBits(dataToEmbed);
            for (int i = 0; i < bits.length && embedOffset + i < result.length; i++) {
                // 只修改字形数据区域
                if (embedOffset + i >= glyfTable.offset &&
                        embedOffset + i < glyfTable.offset + glyfTable.length) {
                    byte originalByte = result[embedOffset + i];
                    byte modifiedByte = (byte) ((originalByte & 0xFE) | (bits[i] ? 1 : 0));
                    result[embedOffset + i] = modifiedByte;
                }
            }
            // 更新字体表校验和（简化处理）
            updateFontChecksums(result, fontTables);
            return result;
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage());
        }
    }

    /**
     * 创建字体隐写头部
     */
    private static byte[] createFontHeader(int messageLength) {
        byte[] header = new byte[32];
        header[0] = (byte) 0x54; // 'T'
        header[1] = (byte) 0x46; // 'F'
        header[2] = (byte) 0x53; // 'S' (TrueFont Steganography)
        header[3] = (byte) 0x01; // 版本
        // 存储消息长度
        header[4] = (byte) ((messageLength >> 24) & 0xFF);
        header[5] = (byte) ((messageLength >> 16) & 0xFF);
        header[6] = (byte) ((messageLength >> 8) & 0xFF);
        header[7] = (byte) (messageLength & 0xFF);
        // 计算校验和
        byte checksum = 0;
        for (int i = 0; i < 8; i++) {
            checksum ^= header[i];
        }
        header[8] = checksum;
        return header;
    }

    /**
     * 更新字体校验和
     */
    private static void updateFontChecksums(byte[] fontData, FontTables fontTables) {
        try {
            // 清除head表的校验和调整值
            FontTables.TableInfo headTable = fontTables.tables.get("head");
            if (headTable != null && headTable.offset + 8 < fontData.length) {
                // head表偏移量16-19是校验和调整值
                fontData[(int) headTable.offset + 8] = 0;
                fontData[(int) headTable.offset + 9] = 0;
                fontData[(int) headTable.offset + 10] = 0;
                fontData[(int) headTable.offset + 11] = 0;
            }
        } catch (Exception e) {
            // 忽略校验和更新错误
        }
    }

    /**
     * 字节转位数组
     */
    private static boolean[] bytesToBits(byte[] bytes) {
        boolean[] bits = new boolean[bytes.length * 8];
        for (int i = 0; i < bytes.length; i++) {
            for (int j = 0; j < 8; j++) {
                bits[i * 8 + j] = ((bytes[i] >> (7 - j)) & 1) == 1;
            }
        }
        return bits;
    }

    /**
     * 字体表结构信息
     */
    private static class FontTables {
        Map<String, TableInfo> tables = new HashMap<>();

        static class TableInfo {
            long checksum;
            long offset;
            long length;

            TableInfo(long checksum, long offset, long length) {
                this.checksum = checksum;
                this.offset = offset;
                this.length = length;
            }
        }
    }
}